﻿/*
* 名称: jQSlider
* 版本: 1.0.0
* 日期: 2017-01-14
* 依赖: jQuery v1.3.1 注意:其它版本的jquery可能会有bug或不能用
* 作者: Conan     email:wensui3#163.com
* 样式: liuhuan
* 
* 参考: 博客园 Jericho 的文章及 Demo （http://www.cnblogs.com/fromearth/archive/2009/07/08/1519054.html）
               Jericho [ thisnamemeansnothing[at]gmail.com ] 
* 用法:
        var slider = $.fn.jQSlider({...});
        slider.setValue(value);
        slider.getValue();
* 
*/
(function ($) {
    $.extend($.fn, {
        jQSlider: function (setting) {
            var ps = $.extend({
                //要渲染的对象，可以为 jquery 选择器，也可以为 jquery 对象
                renderTo: $(document.body),
                //是否能被拖动
                enable: true,
                //是否显示刻度，默认显示均匀刻度，非均匀刻度需自定义
                scale: true,
                //【备注】：initPosition 和 initValue 都可以来初始化默认值，不能同时使 用，如果同时使用将按照 initPosition 的值去做处理
                //滑动器的初始位置，0-width之间，注意不能超出范围
                initPosition: 0,
                //默认值，0-maxValue之间，注意不能超出范围
                initValue: 0,
                //显示的最大值，如10、50、100，最小默认为0，总范围0-10、0-100
                maxValue: 100,
                //可滑动的最小值
                minValue: 0,
                //滑动区域总宽度，容器最终宽度为 width + marginLeft(滑动器width/2) + marginRight(60)
                width: 300,
                //滑动器的宽度，不建议变更
                sliderWidth: 16,
                //提示信息宽度
                tipWidth: 24,
                //滑动时触发事件 参数 res,e   res为滑动结果：0-1之间的小数
                onChanging: function () { },
                //滑动完成触发事件 参数 res,e   res为滑动结果：0-1之间的小数
                onChanged: function () { },
                //附加 自定义刻度表
                customScale: new Array(),
                //附加 自定义值转换成像素宽度
                customValToPosi: function () { },
                //附加 自定义像素宽度转换成值
                customPosiToVal: function () { }
            }, setting);
			
			//获取到要渲染的对象
            ps.renderTo = (typeof ps.renderTo == 'string' ? $(ps.renderTo) : ps.renderTo);
            ps.renderTo.addClass('jq-slider').css("width", ps.width).css('marginLeft', ps.sliderWidth / 2);

            if (ps.initPosition == 0 && ps.initValue != 0) {
                ps.initPosition = Math.ceil((ps.initValue / ps.maxValue) * ps.width);
                if (ps.customScale.length > 0) {
                    ps.initPosition = ps.customValToPosi(ps.initValue);
                } else {
                    ps.initPosition = Math.ceil((ps.initValue / ps.maxValue) * ps.width);
                }
            } else {
                if (ps.customScale.length > 0) {
                    ps.initValue = ps.customPosiToVal(ps.initPosition);
                } else {
                    ps.initValue = Math.ceil((ps.initPosition / ps.width) * ps.maxValue);
                }
            }

            ps.limited = { min: 0 - (ps.sliderWidth / 2), max: ps.width - (ps.sliderWidth / 2) };

            if (ps.minValue != 0) {
                //存在最小值
                if (ps.customScale.length > 0) {
                    //自定义的计算方法
                    ps.limited.min = ps.customValToPosi(ps.minValue) - (ps.sliderWidth) / 2;
                } else {
                    ps.limited.min = Math.ceil((ps.minValue / ps.maxValue) * ps.width) - (ps.sliderWidth) / 2;
                }
            }

            /* ---------->
            <div class="jq-slider-bar">
                <div class="jq-slider-bar-spliter" style="width: 30px;">1</div>
                <div class="jq-slider-bar-spliter" style="width: 30px;">2</div>
            </div>
            <-----------*/
            var sliderbar = $('<div class="jq-slider-bar"></div>').css('width', ps.width).appendTo(ps.renderTo);
            /* ---------->
            <div class="jq-slider-compete">
                <div class="jq-slider-compete-spliter" style="width: 30px;">1</div>
                <div class="jq-slider-compete-spliter" style="width: 30px;">2</div>
            </div>
            <-----------*/
            var completedbar = $('<div class="jq-slider-compete"></div>').css('width', ps.initPosition).appendTo(ps.renderTo);
            //检测是否有刻度或者自定义刻度
            if (ps.scale) {
                var perwidth = ps.width / 10;
                for (var i = 1; i < 11; i++) {
                    $('<div class="jq-slider-bar-spliter" style="width: ' + perwidth + 'px;">' + i / 10 * ps.maxValue + '</div>').appendTo(sliderbar);
                    $('<div class="jq-slider-compete-spliter" style="width: ' + perwidth + 'px;">' + i / 10 * ps.maxValue + '</div>').appendTo(completedbar);
                }
            } else if (ps.customScale.length > 0) {
                for (var i = 0; i < ps.customScale.length; i++) {
                    var item = ps.customScale[i];
                    $('<div class="jq-slider-bar-spliter" style="width: ' + item.width + 'px;">' + item.value + '</div>').appendTo(sliderbar);
                    $('<div class="jq-slider-compete-spliter" style="width: ' + item.width + 'px;">' + item.value + '</div>').appendTo(completedbar);
                }
            }

            var slider = $('<div class="jq-slider-slider"></div>').css('width', ps.sliderWidth).css('left', ps.initPosition - (ps.sliderWidth / 2)).appendTo(ps.renderTo);

            var slidertip = $('<div class="jq-slider-tip"></div>').css('width', ps.tipWidth).css('left', ps.initPosition - (ps.tipWidth / 2)).html(ps.initValue).appendTo(ps.renderTo);

            /*
            <div class="control-input">
                <input type="text" class="number-input" value="1" />
                <span class="number-control">
                    <span class="number-down number-disabled dn"><i class="number-arrow"></i></span>
                    <span class="number-down number-add"><i class="number-arrow"></i></span>
                    <span class="number-up number-cut"><i class="number-arrow"></i></span>
                    <span class="number-up number-disabled dn"><i class="number-arrow"></i></span>
                </span>
            </div>
            */
            var inputdiv = $('<div class="control-input"><input type="text" class="number-input" readonly="readonly" /><span class="number-control"><span class="number-down number-disabled dn"><i class="number-arrow"></i></span><span class="number-down number-add"><i class="number-arrow"></i></span><span class="number-up number-cut"><i class="number-arrow"></i></span><span class="number-up number-disabled dn"><i class="number-arrow"></i></span></span></div>').css('left', ps.width + 10).appendTo(ps.renderTo);
            var inputwrap = inputdiv.find('.number-input');
            var numberadd = inputdiv.find('.number-add');
            var numberaddDisabled = inputdiv.find('.number-down.number-disabled');
            var numbercut = inputdiv.find('.number-cut');
            var numbercutDisabled = inputdiv.find('.number-up.number-disabled');

            if (ps.renderTo.attr('id') != '') {
                inputwrap.attr('id', ps.renderTo.attr('id') + '_input');
            }

			//设置默认值
            inputwrap.val(ps.initValue).attr('oldValue', ps.initValue);
			if (ps.initValue <= ps.minValue) {
				inputwrap.val(ps.minValue);
				numbercut.hide();
				numbercutDisabled.show();
            } else if (ps.initValue >= ps.maxValue) {
				inputwrap.val(ps.maxValue);
				numberadd.hide();
				numberaddDisabled.show();
            } else {
				numberadd.show();
				numbercut.show();
				numberaddDisabled.hide();
				numbercutDisabled.hide();
            }

            //drag and drop
            var slide = {
                drag: function (e) {
                    var d = e.data;
                    var l = Math.min(Math.max(e.pageX - d.pageX + d.left, ps.limited.min), ps.limited.max);
                    jqSliderDealRes(l + (ps.sliderWidth / 2));
                    ps.onChanging((parseInt(l) + (ps.sliderWidth / 2)) / ps.width, e);
                },
                drop: function (e) {
                    ps.onChanged(completedbar.width() / ps.width, e);
                    $(document).off('mousemove', slide.drag).off('mouseup', slide.drop);
                }
            };

            if (ps.enable) {
                //on events
                slider.on('mousedown', function (e) {
                    var d = {
                        left: parseInt(slider.css('left')),
                        pageX: e.pageX
                    };
                    $(document).on('mousemove', d, slide.drag).on('mouseup', d, slide.drop);
                });
                sliderbar.on('click', function (e) {
                    jqSliderBarClick(e);
                });
                completedbar.on('click', function (e) {
                    jqSliderBarClick(e);
                });
                numberadd.on('click', function (e) {
                    inputwrap.val(parseInt(inputwrap.val()) + 1).blur();
                });
                numbercut.on('click', function (e) {
                    inputwrap.val(parseInt(inputwrap.val()) - 1).blur();
                });
                inputwrap.on('blur', function (e) {
                    var val = parseInt(inputwrap.val());
                    if (val < 0) {
                        inputwrap.val(0);
                    } else if (val > ps.maxValue) {
                        inputwrap.val(ps.maxValue);
                    }
                    reg = /^[0-9]*$/;//非零正整数
                    if (!reg.test(inputwrap.val())) {
                        //输入非法
                        inputwrap.val(inputwrap.attr('oldValue'));
                    } else {
                        //输入正确
                        var posi;
                        if (ps.customScale.length > 0) {
                            posi = ps.customValToPosi(inputwrap.val());
                        } else {
                            posi = parseInt(inputwrap.val()) / ps.maxValue * ps.width;
                        }
                        jqSliderDealRes(posi, e, inputwrap.val());
                    }
                }).on('focus', function () {
                    inputwrap.select();
                }).on('keydown', function (e) {
                    if (e.keyCode == 13) {
                        inputwrap.blur();
                    }
                })
            } else {
                inputwrap.attr('disabled', 'disabled');
            }
            function jqSliderBarClick(e) {
                var d = {
                    left: parseInt(slider.css('left')),
                    pageX: ps.renderTo.offset().left + parseInt(slider.css('left')) + (ps.sliderWidth / 2)
                };
                var l = Math.min(Math.max(e.pageX - d.pageX + d.left, ps.limited.min), ps.limited.max);
                jqSliderDealRes(l + (ps.sliderWidth / 2), e);
            }
            function jqSliderDealRes(posi, e, value) {
                slider.css("left", posi - (ps.sliderWidth / 2));
                completedbar.css('width', posi);
                slidertip.css('left', posi - (ps.tipWidth / 2));
                var res;
                if (ps.customScale.length > 0) {
                    res = ps.customPosiToVal(posi);
                } else {
                    res = Math.ceil(parseFloat(posi / ps.width) * ps.maxValue);
                }
                if (typeof value != 'undefined') {
                    res = value;
                }
                if (res == ps.minValue) {
                    numbercut.hide();
                    numbercutDisabled.show();
                } else if (res == ps.maxValue) {
                    numberadd.hide();
                    numberaddDisabled.show();
                } else {
                    numbercut.show();
                    numbercutDisabled.hide();
                    numberadd.show();
                    numberaddDisabled.hide();
                }
                slidertip.html(Math.ceil(res));
                inputwrap.val(Math.ceil(res)).attr('oldValue', res);
                ps.onChanged(completedbar.width() / ps.width, e);
            }
            slider.data = { bar: sliderbar, completed: completedbar, input: inputwrap };

            return slider;
        },
        setValue: function (val) {
            this.data.input.val(val);
            this.data.input.blur();
        },
        getValue: function () {
            return this.data.input.attr('oldValue');
        }
    });
})(jQuery);